#ifndef VMX_H
#define	VMX_H

/*
 * vmx.h: VMX Architecture related definitions
 * Copyright (c) 2004, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place - Suite 330, Boston, MA 02111-1307 USA.
 *
 * A few random additions are:
 * Copyright (C) 2006 Qumranet
 *    Avi Kivity <avi@qumranet.com>
 *    Yaniv Kamay <yaniv@qumranet.com>
 *
 * Copyright 2011 Joyent, Inc.
 */

/*
 * Currently we use one kernel module for all of kvm. This is the entry point
 * for initializing and tearing down the VMX subsystem.
 */
extern int vmx_init(void);
extern void vmx_fini(void);

/*
 * Definitions of Primary Processor-Based VM-Execution Controls.
 */
#define	CPU_BASED_VIRTUAL_INTR_PENDING		0x00000004
#define	CPU_BASED_USE_TSC_OFFSETING		0x00000008
#define	CPU_BASED_HLT_EXITING			0x00000080
#define	CPU_BASED_INVLPG_EXITING		0x00000200
#define	CPU_BASED_MWAIT_EXITING			0x00000400
#define	CPU_BASED_RDPMC_EXITING			0x00000800
#define	CPU_BASED_RDTSC_EXITING			0x00001000
#define	CPU_BASED_CR3_LOAD_EXITING		0x00008000
#define	CPU_BASED_CR3_STORE_EXITING		0x00010000
#define	CPU_BASED_CR8_LOAD_EXITING		0x00080000
#define	CPU_BASED_CR8_STORE_EXITING		0x00100000
#define	CPU_BASED_TPR_SHADOW			0x00200000
#define	CPU_BASED_VIRTUAL_NMI_PENDING		0x00400000
#define	CPU_BASED_MOV_DR_EXITING		0x00800000
#define	CPU_BASED_UNCOND_IO_EXITING		0x01000000
#define	CPU_BASED_USE_IO_BITMAPS		0x02000000
#define	CPU_BASED_USE_MSR_BITMAPS		0x10000000
#define	CPU_BASED_MONITOR_EXITING		0x20000000
#define	CPU_BASED_PAUSE_EXITING			0x40000000
#define	CPU_BASED_ACTIVATE_SECONDARY_CONTROLS	0x80000000
/*
 * Definitions of Secondary Processor-Based VM-Execution Controls.
 */
#define	SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES	0x00000001
#define	SECONDARY_EXEC_ENABLE_EPT		0x00000002
#define	SECONDARY_EXEC_RDTSCP			0x00000008
#define	SECONDARY_EXEC_ENABLE_VPID		0x00000020
#define	SECONDARY_EXEC_WBINVD_EXITING		0x00000040
#define	SECONDARY_EXEC_UNRESTRICTED_GUEST	0x00000080
#define	SECONDARY_EXEC_PAUSE_LOOP_EXITING	0x00000400


#define	PIN_BASED_EXT_INTR_MASK			0x00000001
#define	PIN_BASED_NMI_EXITING			0x00000008
#define	PIN_BASED_VIRTUAL_NMIS			0x00000020

#define	VM_EXIT_HOST_ADDR_SPACE_SIZE		0x00000200
#define	VM_EXIT_ACK_INTR_ON_EXIT		0x00008000
#define	VM_EXIT_SAVE_IA32_PAT			0x00040000
#define	VM_EXIT_LOAD_IA32_PAT			0x00080000

#define	VM_ENTRY_IA32E_MODE			0x00000200
#define	VM_ENTRY_SMM				0x00000400
#define	VM_ENTRY_DEACT_DUAL_MONITOR		0x00000800
#define	VM_ENTRY_LOAD_IA32_PAT			0x00004000

/* VMCS Encodings */
enum vmcs_field {
	VIRTUAL_PROCESSOR_ID		= 0x00000000,
	GUEST_ES_SELECTOR		= 0x00000800,
	GUEST_CS_SELECTOR		= 0x00000802,
	GUEST_SS_SELECTOR		= 0x00000804,
	GUEST_DS_SELECTOR		= 0x00000806,
	GUEST_FS_SELECTOR		= 0x00000808,
	GUEST_GS_SELECTOR		= 0x0000080a,
	GUEST_LDTR_SELECTOR		= 0x0000080c,
	GUEST_TR_SELECTOR		= 0x0000080e,
	HOST_ES_SELECTOR		= 0x00000c00,
	HOST_CS_SELECTOR		= 0x00000c02,
	HOST_SS_SELECTOR		= 0x00000c04,
	HOST_DS_SELECTOR		= 0x00000c06,
	HOST_FS_SELECTOR		= 0x00000c08,
	HOST_GS_SELECTOR		= 0x00000c0a,
	HOST_TR_SELECTOR		= 0x00000c0c,
	IO_BITMAP_A			= 0x00002000,
	IO_BITMAP_A_HIGH		= 0x00002001,
	IO_BITMAP_B			= 0x00002002,
	IO_BITMAP_B_HIGH		= 0x00002003,
	MSR_BITMAP			= 0x00002004,
	MSR_BITMAP_HIGH			= 0x00002005,
	VM_EXIT_MSR_STORE_ADDR		= 0x00002006,
	VM_EXIT_MSR_STORE_ADDR_HIGH	= 0x00002007,
	VM_EXIT_MSR_LOAD_ADDR		= 0x00002008,
	VM_EXIT_MSR_LOAD_ADDR_HIGH	= 0x00002009,
	VM_ENTRY_MSR_LOAD_ADDR		= 0x0000200a,
	VM_ENTRY_MSR_LOAD_ADDR_HIGH	= 0x0000200b,
	TSC_OFFSET			= 0x00002010,
	TSC_OFFSET_HIGH			= 0x00002011,
	VIRTUAL_APIC_PAGE_ADDR		= 0x00002012,
	VIRTUAL_APIC_PAGE_ADDR_HIGH	= 0x00002013,
	APIC_ACCESS_ADDR		= 0x00002014,
	APIC_ACCESS_ADDR_HIGH		= 0x00002015,
	EPT_POINTER			= 0x0000201a,
	EPT_POINTER_HIGH		= 0x0000201b,
	GUEST_PHYSICAL_ADDRESS		= 0x00002400,
	GUEST_PHYSICAL_ADDRESS_HIGH	= 0x00002401,
	VMCS_LINK_POINTER		= 0x00002800,
	VMCS_LINK_POINTER_HIGH		= 0x00002801,
	GUEST_IA32_DEBUGCTL		= 0x00002802,
	GUEST_IA32_DEBUGCTL_HIGH	= 0x00002803,
	GUEST_IA32_PAT			= 0x00002804,
	GUEST_IA32_PAT_HIGH		= 0x00002805,
	GUEST_PDPTR0			= 0x0000280a,
	GUEST_PDPTR0_HIGH		= 0x0000280b,
	GUEST_PDPTR1			= 0x0000280c,
	GUEST_PDPTR1_HIGH		= 0x0000280d,
	GUEST_PDPTR2			= 0x0000280e,
	GUEST_PDPTR2_HIGH		= 0x0000280f,
	GUEST_PDPTR3			= 0x00002810,
	GUEST_PDPTR3_HIGH		= 0x00002811,
	HOST_IA32_PAT			= 0x00002c00,
	HOST_IA32_PAT_HIGH		= 0x00002c01,
	PIN_BASED_VM_EXEC_CONTROL	= 0x00004000,
	CPU_BASED_VM_EXEC_CONTROL	= 0x00004002,
	EXCEPTION_BITMAP		= 0x00004004,
	PAGE_FAULT_ERROR_CODE_MASK	= 0x00004006,
	PAGE_FAULT_ERROR_CODE_MATCH	= 0x00004008,
	CR3_TARGET_COUNT		= 0x0000400a,
	VM_EXIT_CONTROLS		= 0x0000400c,
	VM_EXIT_MSR_STORE_COUNT		= 0x0000400e,
	VM_EXIT_MSR_LOAD_COUNT		= 0x00004010,
	VM_ENTRY_CONTROLS		= 0x00004012,
	VM_ENTRY_MSR_LOAD_COUNT		= 0x00004014,
	VM_ENTRY_INTR_INFO_FIELD	= 0x00004016,
	VM_ENTRY_EXCEPTION_ERROR_CODE	= 0x00004018,
	VM_ENTRY_INSTRUCTION_LEN	= 0x0000401a,
	TPR_THRESHOLD			= 0x0000401c,
	SECONDARY_VM_EXEC_CONTROL	= 0x0000401e,
	PLE_GAP				= 0x00004020,
	PLE_WINDOW			= 0x00004022,
	VM_INSTRUCTION_ERROR		= 0x00004400,
	VM_EXIT_REASON			= 0x00004402,
	VM_EXIT_INTR_INFO		= 0x00004404,
	VM_EXIT_INTR_ERROR_CODE		= 0x00004406,
	IDT_VECTORING_INFO_FIELD	= 0x00004408,
	IDT_VECTORING_ERROR_CODE	= 0x0000440a,
	VM_EXIT_INSTRUCTION_LEN		= 0x0000440c,
	VMX_INSTRUCTION_INFO		= 0x0000440e,
	GUEST_ES_LIMIT			= 0x00004800,
	GUEST_CS_LIMIT			= 0x00004802,
	GUEST_SS_LIMIT			= 0x00004804,
	GUEST_DS_LIMIT			= 0x00004806,
	GUEST_FS_LIMIT			= 0x00004808,
	GUEST_GS_LIMIT			= 0x0000480a,
	GUEST_LDTR_LIMIT		= 0x0000480c,
	GUEST_TR_LIMIT			= 0x0000480e,
	GUEST_GDTR_LIMIT		= 0x00004810,
	GUEST_IDTR_LIMIT		= 0x00004812,
	GUEST_ES_AR_BYTES		= 0x00004814,
	GUEST_CS_AR_BYTES		= 0x00004816,
	GUEST_SS_AR_BYTES		= 0x00004818,
	GUEST_DS_AR_BYTES		= 0x0000481a,
	GUEST_FS_AR_BYTES		= 0x0000481c,
	GUEST_GS_AR_BYTES		= 0x0000481e,
	GUEST_LDTR_AR_BYTES		= 0x00004820,
	GUEST_TR_AR_BYTES		= 0x00004822,
	GUEST_INTERRUPTIBILITY_INFO	= 0x00004824,
	GUEST_ACTIVITY_STATE		= 0X00004826,
	GUEST_SYSENTER_CS		= 0x0000482A,
	HOST_IA32_SYSENTER_CS		= 0x00004c00,
	CR0_GUEST_HOST_MASK		= 0x00006000,
	CR4_GUEST_HOST_MASK		= 0x00006002,
	CR0_READ_SHADOW			= 0x00006004,
	CR4_READ_SHADOW			= 0x00006006,
	CR3_TARGET_VALUE0		= 0x00006008,
	CR3_TARGET_VALUE1		= 0x0000600a,
	CR3_TARGET_VALUE2		= 0x0000600c,
	CR3_TARGET_VALUE3		= 0x0000600e,
	EXIT_QUALIFICATION		= 0x00006400,
	GUEST_LINEAR_ADDRESS		= 0x0000640a,
	GUEST_CR0			= 0x00006800,
	GUEST_CR3			= 0x00006802,
	GUEST_CR4			= 0x00006804,
	GUEST_ES_BASE			= 0x00006806,
	GUEST_CS_BASE			= 0x00006808,
	GUEST_SS_BASE			= 0x0000680a,
	GUEST_DS_BASE			= 0x0000680c,
	GUEST_FS_BASE			= 0x0000680e,
	GUEST_GS_BASE			= 0x00006810,
	GUEST_LDTR_BASE			= 0x00006812,
	GUEST_TR_BASE			= 0x00006814,
	GUEST_GDTR_BASE			= 0x00006816,
	GUEST_IDTR_BASE			= 0x00006818,
	GUEST_DR7			= 0x0000681a,
	GUEST_RSP			= 0x0000681c,
	GUEST_RIP			= 0x0000681e,
	GUEST_RFLAGS			= 0x00006820,
	GUEST_PENDING_DBG_EXCEPTIONS	= 0x00006822,
	GUEST_SYSENTER_ESP		= 0x00006824,
	GUEST_SYSENTER_EIP		= 0x00006826,
	HOST_CR0			= 0x00006c00,
	HOST_CR3			= 0x00006c02,
	HOST_CR4			= 0x00006c04,
	HOST_FS_BASE			= 0x00006c06,
	HOST_GS_BASE			= 0x00006c08,
	HOST_TR_BASE			= 0x00006c0a,
	HOST_GDTR_BASE			= 0x00006c0c,
	HOST_IDTR_BASE			= 0x00006c0e,
	HOST_IA32_SYSENTER_ESP		= 0x00006c10,
	HOST_IA32_SYSENTER_EIP		= 0x00006c12,
	HOST_RSP			= 0x00006c14,
	HOST_RIP			= 0x00006c16,
};

#define	VMX_EXIT_REASONS_FAILED_VMENTRY		0x80000000

#define	EXIT_REASON_EXCEPTION_NMI		0
#define	EXIT_REASON_EXTERNAL_INTERRUPT		1
#define	EXIT_REASON_TRIPLE_FAULT		2

#define	EXIT_REASON_PENDING_INTERRUPT		7
#define	EXIT_REASON_NMI_WINDOW			8
#define	EXIT_REASON_TASK_SWITCH			9
#define	EXIT_REASON_CPUID			10
#define	EXIT_REASON_HLT				12
#define	EXIT_REASON_INVLPG			14
#define	EXIT_REASON_RDPMC			15
#define	EXIT_REASON_RDTSC			16
#define	EXIT_REASON_VMCALL			18
#define	EXIT_REASON_VMCLEAR			19
#define	EXIT_REASON_VMLAUNCH			20
#define	EXIT_REASON_VMPTRLD			21
#define	EXIT_REASON_VMPTRST			22
#define	EXIT_REASON_VMREAD			23
#define	EXIT_REASON_VMRESUME			24
#define	EXIT_REASON_VMWRITE			25
#define	EXIT_REASON_VMOFF			26
#define	EXIT_REASON_VMON			27
#define	EXIT_REASON_CR_ACCESS			28
#define	EXIT_REASON_DR_ACCESS			29
#define	EXIT_REASON_IO_INSTRUCTION		30
#define	EXIT_REASON_MSR_READ			31
#define	EXIT_REASON_MSR_WRITE			32
#define	EXIT_REASON_MWAIT_INSTRUCTION		36
#define	EXIT_REASON_MONITOR_INSTRUCTION		39
#define	EXIT_REASON_PAUSE_INSTRUCTION		40
#define	EXIT_REASON_MCE_DURING_VMENTRY		41
#define	EXIT_REASON_TPR_BELOW_THRESHOLD		43
#define	EXIT_REASON_APIC_ACCESS			44
#define	EXIT_REASON_EPT_VIOLATION		48
#define	EXIT_REASON_EPT_MISCONFIG		49
#define	EXIT_REASON_WBINVD			54

/*
 * Interruption-information format
 */
#define	INTR_INFO_VECTOR_MASK			0xff		/* 7:0 */
#define	INTR_INFO_INTR_TYPE_MASK		0x700		/* 10:8 */
#define	INTR_INFO_DELIVER_CODE_MASK		0x800		/* 11 */
#define	INTR_INFO_UNBLOCK_NMI			0x1000		/* 12 */
#define	INTR_INFO_VALID_MASK			0x80000000	/* 31 */
#define	INTR_INFO_RESVD_BITS_MASK		0x7ffff000

#define	VECTORING_INFO_VECTOR_MASK		INTR_INFO_VECTOR_MASK
#define	VECTORING_INFO_TYPE_MASK		INTR_INFO_INTR_TYPE_MASK
#define	VECTORING_INFO_DELIVER_CODE_MASK	INTR_INFO_DELIVER_CODE_MASK
#define	VECTORING_INFO_VALID_MASK		INTR_INFO_VALID_MASK

#define	INTR_TYPE_EXT_INTR			(0 << 8)
#define	INTR_TYPE_NMI_INTR			(2 << 8)
#define	INTR_TYPE_HARD_EXCEPTION		(3 << 8)
#define	INTR_TYPE_SOFT_INTR			(4 << 8)
#define	INTR_TYPE_SOFT_EXCEPTION		(6 << 8)

/* GUEST_INTERRUPTIBILITY_INFO flags. */
#define	GUEST_INTR_STATE_STI			0x00000001
#define	GUEST_INTR_STATE_MOV_SS			0x00000002
#define	GUEST_INTR_STATE_SMI			0x00000004
#define	GUEST_INTR_STATE_NMI			0x00000008

/*
 * Exit Qualifications for MOV for Control Register Access
 *
 * CONTROL_REG_ACCESS_NUM	2:0, number of control reg.
 * CONTROL_REG_ACCESS_TYPE	5:4, access type
 * CONTROL_REG_ACCESS_SHIFT	10:8, general purpose reg.
 * LMSW_SOURCE_DATA		16:31 lmsw source
 */
#define	CONTROL_REG_ACCESS_NUM		0x7
#define	CONTROL_REG_ACCESS_TYPE		0x30
#define	CONTROL_REG_ACCESS_REG		0xf00
#define	LMSW_SOURCE_DATA_SHIFT		16
#define	LMSW_SOURCE_DATA		(0xFFFF << LMSW_SOURCE_DATA_SHIFT)
#define	REG_EAX				(0 << 8)
#define	REG_ECX				(1 << 8)
#define	REG_EDX				(2 << 8)
#define	REG_EBX				(3 << 8)
#define	REG_ESP				(4 << 8)
#define	REG_EBP				(5 << 8)
#define	REG_ESI				(6 << 8)
#define	REG_EDI				(7 << 8)

/*
 * Exit Qualifications for MOV for Debug Register Access
 *
 * DEBUG_REG_ACCESS_NUM		2:0, number of debug reg.
 * DEBUG_REG_ACCESS_TYPE	4, direction of access
 * DEBUG_REG_ACCESS_REG(eq)	11:8, general purpose reg.
 */
#define	DEBUG_REG_ACCESS_NUM		0x7
#define	DEBUG_REG_ACCESS_TYPE		0x10
#define	TYPE_MOV_TO_DR			(0 << 4)
#define	TYPE_MOV_FROM_DR		(1 << 4)
#define	DEBUG_REG_ACCESS_REG(eq)	(((eq) >> 8) & 0xf)


/* segment AR */
#define	SEGMENT_AR_L_MASK		(1 << 13)

#define	AR_TYPE_ACCESSES_MASK		1
#define	AR_TYPE_READABLE_MASK		(1 << 1)
#define	AR_TYPE_WRITEABLE_MASK		(1 << 2)
#define	AR_TYPE_CODE_MASK		(1 << 3)
#define	AR_TYPE_MASK			0x0f
#define	AR_TYPE_BUSY_64_TSS		11
#define	AR_TYPE_BUSY_32_TSS		11
#define	AR_TYPE_BUSY_16_TSS		3
#define	AR_TYPE_LDT			2

#define	AR_UNUSABLE_MASK		(1 << 16)
#define	AR_S_MASK			(1 << 4)
#define	AR_P_MASK			(1 << 7)
#define	AR_L_MASK			(1 << 13)
#define	AR_DB_MASK			(1 << 14)
#define	AR_G_MASK			(1 << 15)
#define	AR_DPL_SHIFT			5
#define	AR_DPL(ar) 			(((ar) >> AR_DPL_SHIFT) & 3)

#define	AR_RESERVD_MASK	0xfffe0f00

#define	TSS_PRIVATE_MEMSLOT			(KVM_MEMORY_SLOTS + 0)
#define	APIC_ACCESS_PAGE_PRIVATE_MEMSLOT	(KVM_MEMORY_SLOTS + 1)
#define	IDENTITY_PAGETABLE_PRIVATE_MEMSLOT	(KVM_MEMORY_SLOTS + 2)

#define	VMX_NR_VPIDS				(1 << 16)
#define	VMX_VPID_EXTENT_SINGLE_CONTEXT		1
#define	VMX_VPID_EXTENT_ALL_CONTEXT		2

#define	VMX_EPT_EXTENT_INDIVIDUAL_ADDR		0
#define	VMX_EPT_EXTENT_CONTEXT			1
#define	VMX_EPT_EXTENT_GLOBAL			2

#define	VMX_EPT_EXECUTE_ONLY_BIT		(1ull)
#define	VMX_EPT_PAGE_WALK_4_BIT			(1ull << 6)
#define	VMX_EPTP_UC_BIT				(1ull << 8)
#define	VMX_EPTP_WB_BIT				(1ull << 14)
#define	VMX_EPT_2MB_PAGE_BIT			(1ull << 16)
#define	VMX_EPT_1GB_PAGE_BIT			(1ull << 17)
#define	VMX_EPT_EXTENT_INDIVIDUAL_BIT		(1ull << 24)
#define	VMX_EPT_EXTENT_CONTEXT_BIT		(1ull << 25)
#define	VMX_EPT_EXTENT_GLOBAL_BIT		(1ull << 26)

#define	VMX_EPT_DEFAULT_GAW			3
#define	VMX_EPT_MAX_GAW				0x4
#define	VMX_EPT_MT_EPTE_SHIFT			3
#define	VMX_EPT_GAW_EPTP_SHIFT			3
#define	VMX_EPT_DEFAULT_MT			0x6ull
#define	VMX_EPT_READABLE_MASK			0x1ull
#define	VMX_EPT_WRITABLE_MASK			0x2ull
#define	VMX_EPT_EXECUTABLE_MASK			0x4ull
#define	VMX_EPT_IPAT_BIT			(1ull << 6)

#define	VMX_EPT_IDENTITY_PAGETABLE_ADDR		0xfffbc000ul


#define	ASM_VMX_VMCLEAR_RAX		".byte 0x66, 0x0f, 0xc7, 0x30"
#define	ASM_VMX_VMLAUNCH		".byte 0x0f, 0x01, 0xc2"
#define	ASM_VMX_VMRESUME		".byte 0x0f, 0x01, 0xc3"
#define	ASM_VMX_VMPTRLD_RAX		".byte 0x0f, 0xc7, 0x30"
#define	ASM_VMX_VMREAD_RDX_RAX		".byte 0x0f, 0x78, 0xd0"
#define	ASM_VMX_VMWRITE_RAX_RDX		".byte 0x0f, 0x79, 0xd0"
#define	ASM_VMX_VMWRITE_RSP_RDX		".byte 0x0f, 0x79, 0xd4"
#define	ASM_VMX_VMXOFF			".byte 0x0f, 0x01, 0xc4"
#define	ASM_VMX_VMXON_RAX		".byte 0xf3, 0x0f, 0xc7, 0x30"
#define	ASM_VMX_INVEPT			".byte 0x66, 0x0f, 0x38, 0x80, 0x08"
#define	ASM_VMX_INVVPID			".byte 0x66, 0x0f, 0x38, 0x81, 0x08"



#endif
